package retrofix;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

import retrofix.api.BiliService;
import retrofix.api.constants.ApiConstants;
import retrofix.entity.BiliDingVideo;
import retrofit2.Call;
import retrofit2.CallAdapter;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import rx.Observable;
import rx.Scheduler;
import rx.Subscriber;
import rx.schedulers.Schedulers;

import static rx.schedulers.Schedulers.io;

public final class RxJavaObserveOnMainThread {
    public static void main(String... args) {
        Scheduler observeOn = Schedulers.computation(); // Or use mainThread() for Android.

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(ApiConstants.BILI_BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(new ObserveOnMainCallAdapterFactory(observeOn))
                .addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(io()))
                .build();


        BiliService service = retrofit.create(BiliService.class);
        service.getDingVideosRx()
                .subscribeOn(Schedulers.io())
                .subscribe(new Subscriber<BiliDingVideo>() {
                    public void onCompleted() {

                        System.out.println("onCompleted");
                    }

                    public void onError(Throwable e) {

                        System.err.println("onError");
                    }

                    public void onNext(BiliDingVideo biliDingVideo) {

                        System.out.println(biliDingVideo);
                    }
                });

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    static final class ObserveOnMainCallAdapterFactory extends CallAdapter.Factory {
        final Scheduler scheduler;

        ObserveOnMainCallAdapterFactory(Scheduler scheduler) {
            this.scheduler = scheduler;
        }

        @Override
        public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
            if (getRawType(returnType) != Observable.class) {
                return null; // Ignore non-Observable types.
            }

            // Look up the next call adapter which would otherwise be used if this one was not present.
            //noinspection unchecked returnType checked above to be Observable.
            final CallAdapter<Object, Observable<?>> delegate =
                    (CallAdapter<Object, Observable<?>>) retrofit.nextCallAdapter(this, returnType,
                            annotations);

            return new CallAdapter<Object, Object>() {
                public Object adapt(Call<Object> call) {
                    // Delegate to get the normal Observable...
                    Observable<?> o = delegate.adapt(call);
                    // ...and change it to send notifications to the observer on the specified scheduler.
                    return o.observeOn(scheduler);
                }

                public Type responseType() {
                    return delegate.responseType();
                }
            };
        }
    }
}